package com.litchi.tutor.common.util;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author hoby
 * @since 2021-08-19
 */
@Slf4j
@Component
public class RedisUtil {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    ValueOperations<String, Object> stringOps;
    ListOperations<String, Object> listOps;
    SetOperations<String, Object> setOps;
    ZSetOperations<String, Object> zSetOps;
    HashOperations<String, String, Object> hashOps;

    @PostConstruct
    public void init() {
        stringOps = redisTemplate.opsForValue();
        listOps = redisTemplate.opsForList();
        setOps = redisTemplate.opsForSet();
        zSetOps = redisTemplate.opsForZSet();
        hashOps = redisTemplate.opsForHash();
    }


    public void deleteKey(String key) {
        redisTemplate.delete(key);
    }


    public Boolean keyExists(String key) {
        return redisTemplate.hasKey(key);
    }

    public void set(String key, String value) {
        stringOps.set(key, value);
    }

    public void set(String key, Object value) {
        stringOps.set(key, JSON.toJSONString(value));
    }

    public void set(String key, String value, long l, TimeUnit timeUnit) {
        stringOps.set(key, value, l, timeUnit);
    }

    public boolean lock(String key, String value, int seconds) {
        try {
            Boolean result = stringOps.setIfAbsent(key, value, seconds, TimeUnit.SECONDS);
            if (result != null) {
                return result;
            }
        } catch (Throwable e) {
            log.error("key:{},lock error", key);
            log.error("error info:", e);
        }
        return false;
    }

    public void expire(String key, int seconds) {
        redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
    }

    public void setAndExpire(String key, String value, int seconds) {
        stringOps.set(key, value, seconds, TimeUnit.SECONDS);
    }

    public boolean setNx(String key, String value) {
        return stringOps.setIfAbsent(key, value);
    }

    public boolean setNx(String key, String value, int seconds) {
        return stringOps.setIfAbsent(key, value, seconds, TimeUnit.SECONDS);
    }

    public void incr(String key) {
        stringOps.increment(key, 1L);
    }

    public void decr(String key) {
        stringOps.decrement(key, 1L);
    }

    public void incrBy(String key, Long value) {
        stringOps.increment(key, value);
    }

    public void decrBy(String key, Long value) {
        stringOps.decrement(key, value);
    }

    public String get(String key) {
        return Convert.toStr(stringOps.get(key), "");
    }

    public Boolean zadd(String key, Double score, String value) {
        return zSetOps.add(key, value, score);
    }

    public Long zcard(String key) {
        return zSetOps.zCard(key);
    }

    public String zscore(String key, String value) {
        return String.valueOf(zSetOps.score(key, value));
    }

    public Long zrevrank(String key, String value) {
        return zSetOps.reverseRank(key, value);
    }

    public void zincrBy(String key, Double score, String value) {
        zSetOps.incrementScore(key, value, score);
    }

    public Long zrank(String key, String value) {
        return zSetOps.rank(key, value);
    }

    public Set<Object> zrevrange(String key, long start, long end) {
        return zSetOps.reverseRange(key, start, end);
    }

    public void lpushMulti(String key, int count) {
        String[] strings = new String[count];
        for (int i = 0; i < count; i++) {
            strings[i] = "1";
        }
        listOps.leftPushAll(key, strings);
    }

    public void rpush(String key, String count) {
        listOps.rightPushAll(key, count);
    }

    public void lremMulti(String key, String value, int count) {
        listOps.remove(key, count, value);
    }

    public Long lpush(String key, String value) {
        return listOps.leftPush(key, value);
    }

    public String popList(String key) {
        return (String) listOps.rightPop(key);
    }

    public Long getListSize(String key) {
        return listOps.size(key);
    }

    public Boolean expireAt(String key, Date expireTime) {
        return redisTemplate.expireAt(key, expireTime);
    }

    public void hIncrBy(String key, String field, long count) {
        hashOps.increment(key, field, count);
    }

    public Map<String, Object> hGetAll(String key) {
        return hashOps.entries(key);
    }

    public Object hGet(String key, String field) {
        return hashOps.get(key, field);
    }

    public void hSet(String key, String field, Object value) {
        hashOps.put(key, field, value);
    }

    public void hSetAll(String key, Map<String, Object> values) {
        hashOps.putAll(key, values);
    }

    public Long sadd(String key, String value) {
        return setOps.add(key, value);
    }

    public Boolean sisMember(String key, String value) {
        return setOps.isMember(key, value);
    }

    public Long scard(String key) {
        return setOps.size(key);
    }

}
